/*******************************************************************************
版权声明: Copyright(C) HT-Tech Co., Ltd. 2020-2021. All rights reserved.
文件名称: httun.c
文件描述: 隧道操作实现
创 建 者: 陈位仅
创建时间: 2024年11月13日
修改历史:
1. 2024年11月13日   陈位仅      创建文件 
*******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <net/if.h>
#include <net/route.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <linux/if_tun.h>

#include "htmacro.h"
#include "htcfg.h"
#include "htssl.h"
#include "httun.h"

// 创建虚拟网卡
int httun_create(IN ht_cfg_t *pcfg, OUT htssl_info_t *pInfo)
{
    int fd;             // 通信描述符
    struct ifreq ifr;   // 设备控制结构

    // 打开虚拟网卡设备节点
    if ((fd = open(TUN_DEV, O_RDWR)) < 0) {
        printf("open(%s). %s(%d)\n", TUN_DEV, strerror(errno), errno);
        return -1;
    }

    // 设备虚拟网卡通信模式
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, pcfg->tunnel, IFNAMSIZ);
    ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
    if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) {
        printf("ioctl(TUNSETIFF). %s(%d)\n", strerror(errno), errno);
        close(fd);
        return -1;
    }

    //输出通信描述符
    pInfo->fdTun = fd;

    return 0;
}

// 配置虚拟网卡IP和掩码
int httun_setup(IN ht_cfg_t *pcfg, IN char *addr, IN char *mask)
{
    int fd;                 // 通信描述符
    struct ifreq ifr;       // 设备控制结构
    struct sockaddr_in sa;  // 地址结构

    // 参数检查
    if (NULL == pcfg || NULL == addr || NULL == mask) {
        return -1;
    }

    // 打开控制套接字
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        printf("socket(SOCK_DGRAM). %s(%d)\n", strerror(errno), errno);
        goto EXITERR;
    }

    // 配置虚拟网卡
    memset(&ifr, 0, sizeof(struct ifreq));
    strncpy(ifr.ifr_name, pcfg->tunnel, IFNAMSIZ);

    // 获取虚拟网卡状态
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
        printf("ioctl(SIOCGIFFLAGS). %s(%d)\n", strerror(errno), errno);
        goto EXITERR;
    }

    // 设置虚拟网卡为UP状态
    ifr.ifr_flags |= IFF_UP;
    if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
        printf("ioctl(SIOCSIFFLAGS|IFF_UP). %s(%d)\n", strerror(errno), errno);
        goto EXITERR;
    }

    // 设置虚拟网卡为混杂模式
    ifr.ifr_flags |= IFF_PROMISC;
    if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
        printf("ioctl(SIOCSIFFLAGS|IFF_PROMISC). %s(%d)\n", strerror(errno), errno);
        goto EXITERR;
    }

    // 设置虚拟网卡IP地址信息
    memset(&sa, 0, sizeof(struct sockaddr_in));
    sa.sin_family = AF_INET;
    inet_pton(AF_INET, addr, &sa.sin_addr.s_addr);

    // 设置虚拟网卡地址
    memcpy(&ifr.ifr_addr, &sa, sizeof(struct sockaddr));
    if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) {
        printf("ioctl(SIOCSIFADDR). %s(%d)\n", strerror(errno), errno);
        goto EXITERR;
    }

    // 设置虚拟网卡掩码信息
    memset(&sa, 0, sizeof(struct sockaddr_in));
    sa.sin_family = AF_INET;
    inet_pton(AF_INET, mask, &sa.sin_addr.s_addr);
    memcpy(&ifr.ifr_netmask, &sa, sizeof(struct sockaddr));

    // 设置虚拟网卡掩码
    if (ioctl(fd, SIOCSIFNETMASK, &ifr) < 0) {
        printf("ioctl(SIOCSIFNETMASK). %s(%d)\n", strerror(errno), errno);
        goto EXITERR;
    }

    // 关闭控制套接字
    close(fd);

    return 0;

EXITERR:
    // 关闭控制套接字
    close(fd);

    return -1;
}

// 从虚拟网卡接收数据
int httun_recv(IN htssl_info_t *pInfo, OUT void *buf, IN int len)
{
    int rBytes = 0;

    if (NULL == buf) {
        return -1;
    }

    // 接收数据
    rBytes = read(pInfo->fdTun, buf, len);

    return rBytes;
}

// 发送数据到虚拟网卡
int httun_send(IN htssl_info_t *pInfo, IN void *buf, IN int len)
{
    int sBytes = 0;

    if (NULL == buf) {
        return -1;
    }

    // 发送数据
    do {
        sBytes += write(pInfo->fdTun, buf, len);
    } while (sBytes < len);

    return 0;
}

// 关闭虚拟网卡
void httun_close(IN htssl_info_t *pInfo)
{
    // 关闭虚拟网卡
    if (pInfo->fdTun >= 0) {
        close(pInfo->fdTun);
    }
}

// 配置系统路由
int httun_route(IN ht_cfg_t *pcfg, IN char *ip)
{
    int skfd;                   // 通信描述符
    struct rtentry rt;          // 路由控制结构
    struct sockaddr_in dst;     // 目标地址结构
    struct sockaddr_in gw;      // 网关地址结构
    struct sockaddr_in genmask; // 通用掩码结构

    // 设置默认路由
    memset(&rt, 0, sizeof(rt));
    genmask.sin_addr.s_addr = inet_addr("0.0.0.0");

    // 1.魔数
    rt.rt_metric = 0;
    // 2.地址
    bzero(&dst, sizeof(struct sockaddr_in));
    dst.sin_family = AF_INET;
    dst.sin_addr.s_addr = inet_addr("0.0.0.0");
    rt.rt_dst = *(struct sockaddr *)&dst;
    // 3.掩码
    bzero(&dst, sizeof(struct sockaddr_in));
    genmask.sin_family = AF_INET;
    genmask.sin_addr.s_addr = htonl(INADDR_ANY);
    rt.rt_genmask = *(struct sockaddr *)&genmask;

    // 4.网关
    bzero(&dst, sizeof(struct sockaddr_in));
    gw.sin_family = AF_INET;
    gw.sin_addr.s_addr = inet_addr(ip);
    rt.rt_gateway = *(struct sockaddr *)&gw;

    // 5.接口
    rt.rt_dev = pcfg->tunnel;
    rt.rt_flags = RTF_GATEWAY;
    skfd = socket(AF_INET, SOCK_STREAM, 0);
    if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
        printf("Error route add :%d\n", errno);
        return -1;
    }

    return 0;
}
